package ui.troopmanager.mooresr.us;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.ListIterator;
import java.util.Set;
import java.util.Stack;
import java.util.TreeSet;

import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.AbstractTableModel;

import troopmanager.mooresr.us.DataManager;
import troopmanager.mooresr.us.Event;
import troopmanager.mooresr.us.EventParticipant;
import troopmanager.mooresr.us.EventSpecialForm;
import troopmanager.mooresr.us.EventSpecialFormName;
import troopmanager.mooresr.us.Person;
import troopmanager.mooresr.us.SortedListModel;

/**
 * @author christopher_moore
 *
 */

public class ParticipantsDialog extends JDialog {
	private static final long serialVersionUID = 1L;
	
	private JPanel topPanel;
	private JList leftList;
	private SortedListModel<Person> leftListModel;
	private JScrollPane leftScrollPane;
	private JPanel buttonPanel;
	private JButton addButton;
	private JButton removeButton;
	private JTable rightList;
	private ParticipantTableModel rightListModel;
	private JScrollPane rightScrollPane;
	private JLabel attendeeCountLabel;
	private JPanel bottomPanel;
	private JButton okButton;
	private JButton cancelButton;
	
	private Integer eventId;
	private Integer adultMale;
	private Integer adultFemale;
	private Integer youthMale;
	private Integer youthFemale;
	
	public ParticipantsDialog() {
		initComponents();
	}
	
	private class DataRow implements Comparable<DataRow> {
		EventParticipant ep;
		HashMap<Integer,EventSpecialForm> specialForms;
		
		public DataRow(EventParticipant ep) {
			this.ep = ep;
			specialForms = new HashMap<Integer, EventSpecialForm>();
		}
		
		public Person getPerson() {
			return ep.getPerson();
		}
		
		public Boolean getPaid() {
			return ep.getPaid();
		}
		
		public Boolean getPermissionSlip() {
			return ep.getPermissionSlip();
		}
		
		public EventParticipant getEventParticipant() {
			return ep;
		}
		
		public void setPaid(Boolean paid) {
			ep.setPaid(paid);
		}
		
		public void setPermissionSlip(Boolean permissionSlip) {
			ep.setPermissionSlip(permissionSlip);
		}
		
		public Boolean getFormReceived(Integer formId) {
			EventSpecialForm esf = specialForms.get(formId);
			
			if (esf == null) {
				return false;
			} else {
				return esf.getReceived();
			}

		}
		
		public void setFormReceived(Integer formId, Integer personId, Boolean value) {
			EventSpecialForm esf = specialForms.get(formId);
			
			if (esf == null) {
				esf = new EventSpecialForm(formId, personId, value);
				specialForms.put(formId, esf);
			} else {
				esf.setReceived(value);
			}
		}

		@Override
		public int compareTo(DataRow other) {
			return this.ep.compareTo(other.getEventParticipant());
		}
		
		public void addEventSpecialForms(Set<EventSpecialForm> formSet) {
			for (EventSpecialForm esf : formSet) {
				specialForms.put(esf.getForm_id(), esf);
			}
		}
		
		public HashMap<Integer, EventSpecialForm> getSpecialForms() {
			return specialForms;
		}
	}
	
	private class ParticipantTableModel extends AbstractTableModel {
		private static final long serialVersionUID = 1L;
		private ArrayList<String> columnNames;
		private TreeSet<DataRow> data;
		private HashMap<Integer,Integer> columnFormIdMap;
		
		public ParticipantTableModel() {
			data = new TreeSet<DataRow>();
			
			columnNames = new ArrayList<String>();
			columnNames.add("Name");
			columnNames.add("Paid");
			columnNames.add("Permission Slip");
			
			columnFormIdMap = new HashMap<Integer, Integer>();
			
		}
		
		@Override
		public int getColumnCount() {
			return columnNames.size();
		}

		@Override
		public int getRowCount() {
			return data.size();
		}

		@Override
		public Object getValueAt(int row, int col) {
			DataRow rowData = (DataRow) data.toArray()[row];
			switch(col) {
			case 0:
				return rowData.getPerson().toString();
			case 1:
				return rowData.getPaid();
			case 2:
				return rowData.getPermissionSlip();
			default:
				return rowData.getFormReceived(columnFormIdMap.get(col));
			}
		}
		
		public void setValueAt(Object value, int row, int col) {
			DataRow rowData = (DataRow) data.toArray()[row];
			
			switch(col) {
			case 1:
				rowData.setPaid((Boolean)value);
				break;
			case 2:
				rowData.setPermissionSlip((Boolean)value);
				break;
			default:
				rowData.setFormReceived(columnFormIdMap.get(col), rowData.getPerson().getPersonId(), (Boolean)value);
			}
		}
		public boolean isCellEditable(int row, int col) {
			if (col > 0) {
				return true;
			} else {
				return false;
			}
		}
		
		@SuppressWarnings("unchecked")
		public Class getColumnClass(int col) {
			try {
				if (col > 0) {
					return Class.forName("java.lang.Boolean");
				} else {
					return Class.forName("java.lang.String");
				}
			} catch (ClassNotFoundException e) {
				return null;
			}
		}
		
		public String getColumnName(int col) {
			return columnNames.get(col);
		}
		
		public void addColumn(Integer formId, String formName) {
			int numColumns = columnNames.size();
			
			columnFormIdMap.put(numColumns, formId);
			columnNames.add(formName);
		}
		
		public void addElement(DataRow rowData) {
			data.add(rowData);
			fireTableDataChanged();
		}
		
		public DataRow get(int index) {
			return (DataRow) data.toArray()[index];
		}
		
		public DataRow remove(int index) {
			DataRow o = (DataRow) get(index);
			boolean removed = data.remove(o);
			if (removed) {
				fireTableDataChanged();
			}
			return o;
		}
		
		public void clear() {
			data.clear();
			fireTableDataChanged();
		}
	}
	
	private void initComponents() {
		BorderLayout layout = new BorderLayout();
	
		
		setTitle("Event Participants");
		setFont(new Font("Dialog", Font.PLAIN, 12));
		setBackground(Color.white);
		setForeground(Color.black);

		setLayout(layout);
		
		topPanel = new JPanel();
		leftListModel = new SortedListModel<Person>();
		leftList = new JList(leftListModel);
		leftScrollPane = new JScrollPane();
		leftScrollPane.setViewportView(leftList);
		attendeeCountLabel = new JLabel("Attendees:");
		buttonPanel = new JPanel();
		addButton = new JButton("Add -->");
		removeButton = new JButton("<-- Remove");
		/*
		rightListModel = new ParticipantTableModel();
		rightList = new JTable(rightListModel);
		*/
		rightList = new JTable();
		rightScrollPane = new JScrollPane();
		rightScrollPane.setViewportView(rightList);
		bottomPanel = new JPanel();
		okButton = new JButton("OK");
		cancelButton = new JButton("Cancel");
		
		okButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent event) {
				okButtonCallback(event);
			}
		});
		
		cancelButton.addActionListener(new ActionListener() {		
			public void actionPerformed(ActionEvent event) {
				cancelButtonCallback(event);
			}
		});
		
		addButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent event) {
				addButtonCallback(event);
			}
		});
		
		removeButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent event) {
				removeButtonCallback(event);
			}
		});
		
		buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.PAGE_AXIS));
		buttonPanel.add(addButton);
		buttonPanel.add(removeButton);
		
		topPanel.setLayout(new BoxLayout(topPanel, BoxLayout.LINE_AXIS));
		topPanel.add(leftScrollPane);
		topPanel.add(buttonPanel);
		topPanel.add(rightScrollPane);
		
		bottomPanel.setLayout(new BoxLayout(bottomPanel, BoxLayout.LINE_AXIS));
		bottomPanel.add(okButton);
		bottomPanel.add(cancelButton);
		bottomPanel.add(attendeeCountLabel);
		
		add(topPanel, BorderLayout.CENTER);
		add(bottomPanel, BorderLayout.SOUTH);
		
		setSize(600, 400);
		setModal(true);
	}
	
	private void okButtonCallback(ActionEvent event) {
		LinkedList<EventParticipant> participants = new LinkedList<EventParticipant>();
		Set<EventSpecialForm> allEventSpecialForms = new HashSet<EventSpecialForm>();
				
		for (int i=0; i<rightListModel.getRowCount(); i++) {
			DataRow rowData = (DataRow) rightListModel.get(i);
			EventParticipant ep = rowData.getEventParticipant();
			participants.add(ep);
			HashMap<Integer, EventSpecialForm> esf = rowData.getSpecialForms();
			allEventSpecialForms.addAll(esf.values());
		}
		
		DataManager.getInstance().setEventParticipants(eventId, participants);
		
		DataManager.getInstance().setSpecialForms(allEventSpecialForms);
		
		setVisible(false);
	}
	
	private void cancelButtonCallback(ActionEvent event) {
		setVisible(false);
	}
	
	private void addButtonCallback(ActionEvent event) {
		Stack<Integer> selectedList = new Stack<Integer>();
		
		for (int i=0; i<leftListModel.size(); i++) {
			if (leftList.isSelectedIndex(i)) {
				selectedList.push(i);
			}
		}
		
		while (!selectedList.empty()) {
			int i = selectedList.pop();
			Person p = (Person) leftListModel.remove(i);
			EventParticipant ep = new EventParticipant(eventId, p);
			DataRow rowData = new DataRow(ep);
			rightListModel.addElement(rowData);
			if (p.getType() == Person.ADULT) {
				if (p.getGender().equals("M")) {
					adultMale++;
				} else {
					adultFemale++;
				}
			} else {
				if (p.getGender().equals("M")) {
					youthMale++;
				} else {
					youthFemale++;
				}
			}
		}
		
		updateAttendeeCount();
	}
	
	private void removeButtonCallback(ActionEvent event) {
		Stack<Integer> selectedList = new Stack<Integer>();
		
		for (int i=0; i<rightListModel.getRowCount(); i++) {
			if (rightList.isRowSelected(i)) {
				selectedList.push(i);
			}
		}
		
		while (!selectedList.empty()) {
			int i = selectedList.pop();
			DataRow rowData = (DataRow) rightListModel.remove(i);
			EventParticipant ep = rowData.getEventParticipant();
			Person p = ep.getPerson();
			leftListModel.addElement(p);
			
			if (p.getType() == Person.ADULT) {
				if (p.getGender().equals("M")) {
					adultMale--;
				} else {
					adultFemale--;
				}
			} else {
				if (p.getGender().equals("M")) {
					youthMale--;
				} else {
					youthFemale--;
				}
			}
		}		
		
		updateAttendeeCount();
	}
	
	public void loadData(Event e) {
		LinkedList<EventParticipant> eventParticipants = (LinkedList<EventParticipant>) DataManager.getInstance().getEventParticipants(e);
		LinkedList<Person> allPeople = (LinkedList<Person>) DataManager.getInstance().getAllPeople();

		adultMale = 0;
		adultFemale = 0;
		youthMale = 0;
		youthFemale = 0;
		
		eventId = e.getEventId();
		
		rightListModel = new ParticipantTableModel();
		for (EventSpecialFormName formName : e.getSpecialFormNames()) {
			rightListModel.addColumn(formName.getFormId(), formName.getFormName());
		}
		rightList.setModel(rightListModel);
		
		leftListModel.clear();
		rightListModel.clear();
		
		for (EventParticipant ep : eventParticipants) {
			Person p = ep.getPerson();
			Integer personId = p.getPersonId();
			
			for (ListIterator<Person> l = allPeople.listIterator(); l.hasNext(); ) {
				if (l.next().getPersonId() == p.getPersonId()) {
					l.remove();
				}
			}
			
			DataRow rowData = new DataRow(ep);
			HashSet<EventSpecialForm> esf = (HashSet<EventSpecialForm>) DataManager.getInstance().getSpecialForms(eventId, personId);
			rowData.addEventSpecialForms(esf);
			rightListModel.addElement(rowData);
			
			if (p.getType() == Person.ADULT){
				if (p.getGender().equals("M")) {
					++adultMale;
				} else {
					++adultFemale;
				}
			} else {
				if (p.getGender().equals("M")) {
					++youthMale;
				} else {
					++youthFemale;
				}
			}
		}
		
		for (Person p : allPeople) {
			leftListModel.addElement(p);
		}
		

		updateAttendeeCount();
		
	}

	private void updateAttendeeCount() {
		String attendeeString = "Female Youth: " + youthFemale.toString() +
		"  Female Adults: " + adultFemale.toString() +
		"  Male Youth: " + youthMale.toString() + 
		"  Male Adult: " + adultMale.toString();
		attendeeCountLabel.setText(attendeeString);
	}

}
